/**************************************************************************************************
	$Header: /pub/cvsroot/mydns/src/lib/rr.c,v 1.19 2002/08/31 05:55:41 bboy Exp $

	Copyright (C) 2002  Don Moore <bboy@bboy.net>

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at Your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
**************************************************************************************************/

#include "mydns.h"

char mydns_rr_table_name[PATH_MAX] = MYDNS_RR_TABLE;

/* Optional columns */
int mydns_rr_use_active = 0;
int mydns_rr_use_stamp = 0;


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	MYDNS_RR_COUNT
	Returns the number of records in the rr table.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
u_int32_t
mydns_rr_count(mysql)
	MYSQL *mysql;
{
	MYSQL_RES *res = NULL;
	MYSQL_ROW row;
	char query[512];
	size_t querylen;
	u_int32_t rv = 0;

	querylen = snprintf(query, sizeof(query), "SELECT COUNT(*) FROM %s", mydns_rr_table_name);
	if (mysql_real_query(mysql, query, querylen) || !(res = mysql_store_result(mysql)))
		return (-1);
	if ((row = mysql_fetch_row(res)))
		rv = (u_int32_t)strtoul(row[0], (char **)NULL, 10);
	mysql_free_result(res);
	return (rv);
}
/*--- mydns_rr_count() --------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	MYDNS_SET_RR_TABLE_NAME
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void
mydns_set_rr_table_name(name)
	char *name;
{
	if (!name)
		strncpy(mydns_rr_table_name, MYDNS_RR_TABLE, sizeof(mydns_rr_table_name)-1);
	else
		strncpy(mydns_rr_table_name, name, sizeof(mydns_rr_table_name)-1);
}
/*--- mydns_set_rr_table_name() -----------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	MYDNS_PARSE_RR
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
inline MYDNS_RR *
mydns_parse_rr(row)
	MYSQL_ROW row;
{
	MYDNS_RR *rv;
	register u_char *type;

	if ((rv = (MYDNS_RR *)calloc(1, sizeof(MYDNS_RR))))
	{
		rv->next = NULL;

		rv->id = atou(row[0]);
		rv->zone = atou(row[1]);
		strncpy(rv->name, row[2], sizeof(rv->name)-1);
		strncpy(rv->data, row[3], sizeof(rv->data)-1);
		rv->aux = atou(row[4]);
		rv->ttl = atou(row[5]);

		type = row[6];
		switch (toupper(*type))
		{
			case 'A':
				if (type[1])		/* `AAAA' */
					rv->type = DNS_T_AAAA;
				else					/* `A' */
					rv->type = DNS_T_A;
				break;

			case 'C':				/* `CNAME' */
				rv->type = DNS_T_CNAME;
				break;
			
			case 'M':				/* `MX' */
				rv->type = DNS_T_MX;
				break;

			case 'N':				/* `NS' */
				rv->type = DNS_T_NS;
				break;

			case 'T':				/* `TXT' */
				rv->type = DNS_T_TXT;
				break;

			default:
				rv->type = 0;
				break;
		}
	}
	return (rv);
}
/*-----------------------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	MYDNS_RR_DUP
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
MYDNS_RR *
mydns_rr_dup(start, recurse)
	MYDNS_RR *start;
	int recurse;
{
	register MYDNS_RR *first = NULL, *last = NULL, *rr, *s, *tmp;

	for (s = start; s; s = tmp)
	{
		tmp = s->next;

		if ((rr = (MYDNS_RR *)malloc(sizeof(MYDNS_RR))))
		{
			rr->id = s->id;
			rr->zone = s->zone;
			strncpy(rr->name, s->name, sizeof(rr->name)-1);
			rr->type = s->type;
			strncpy(rr->data, s->data, sizeof(rr->data)-1);
			rr->aux = s->aux;
			rr->ttl = s->ttl;
			rr->next = NULL;
			if (recurse)
			{
				if (!first) first = rr;
				if (last) last->next = rr;
				last = rr;
			}
			else
				return (rr);
		}
	}
	return (first);
}
/*-----------------------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	MYDNS_RR_SIZE
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
inline size_t
mydns_rr_size(first)
	MYDNS_RR *first;
{
	register MYDNS_RR *p;
	register size_t size = 0;

	for (p = first; p; p = p->next)
		size += sizeof(MYDNS_RR) + strlen(p->name) + strlen(p->data);

	return (size);
}
/*-----------------------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	_MYDNS_RR_FREE
	Frees the pointed-to structure.	Don't call this function directly, call the macro.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
inline void
_mydns_rr_free(first)
	MYDNS_RR *first;
{
	register MYDNS_RR *p, *tmp;

	for (p = first; p; p = tmp)
	{
		tmp = p->next;

		free(p);
	}
}
/*-----------------------------------------------------------------------------------------------*/


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
	MYDNS_RR_LOAD
	Returns 0 on success or nonzero if an error occurred.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int
mydns_rr_load(mysql, rptr, zone, type, name, origin)
	MYSQL	*mysql;				/* Open MySQL connection */
	MYDNS_RR **rptr;			/* Result list will be returned here */
	u_int32_t zone;			/* The zone to look in */
	dns_qtype_t type;			/* The RR type to find (may be ANY) */
	u_char *name;				/* The name to look for */
	u_char *origin;			/* Zone origin */
{
	MYDNS_RR  *first = NULL, *last = NULL;
	size_t	 namelen, querylen;
	u_char	 query[DNS_QUERYBUFSIZ], namequery[DNS_MAXNAMELEN + DNS_MAXNAMELEN + DNS_MAXNAMELEN + 25];
	u_char	 *wheretype;
	u_char	 esc[DNS_MAXNAMELEN + DNS_MAXNAMELEN + 1];
	MYSQL_RES *res;
	MYSQL_ROW row;

	if (rptr) *rptr = NULL;
	MYDNS_CLEARERR(mysql)

	/* Verify args */
	if (!mysql || !rptr || !name)
	{
		errno = EINVAL;
		return (-1);
	}

	/* Get the type='XX' part of the WHERE clause */
	switch (type)
	{
		case DNS_T_A:		wheretype = " AND type='A'"; break;
		case DNS_T_AAAA:	wheretype = " AND type='AAAA'"; break;
		case DNS_T_CNAME:	wheretype = " AND type='CNAME'"; break;
		case DNS_T_MX:		wheretype = " AND type='MX'"; break;
		case DNS_T_NS:		wheretype = " AND type='NS'"; break;
		case DNS_T_PTR:	wheretype = " AND type='PTR'"; break;
		case DNS_T_SOA:	wheretype = " AND type='SOA'"; break;
		case DNS_T_TXT:	wheretype = " AND type='TXT'"; break;
		case DNS_T_ANY:	wheretype = ""; break;
		default:
			errno = EINVAL;
			return (-1);
	}

	/* Construct query */
	namelen = strlen(name);
	if (namelen + namelen + 1 > sizeof(esc))
	{
		errno = EINVAL;
		return (-1);
	}
	mysql_real_escape_string(mysql, esc, name, namelen);
	if (origin)
	{
		u_char origin_esc[DNS_MAXNAMELEN + DNS_MAXNAMELEN + 1];
	
		mysql_real_escape_string(mysql, origin_esc, origin, strlen(origin));
		snprintf(namequery, sizeof(namequery), "(NAME='%s' OR name='%s.%s')", esc, esc, origin_esc);
	}
	else
		snprintf(namequery, sizeof(namequery), "NAME='%s'", esc);

	querylen = snprintf(query, sizeof(query),
		"SELECT "MYDNS_RR_FIELDS" FROM %s WHERE "
			"zone=%u%s AND %s%s", mydns_rr_table_name, zone, wheretype, namequery,
			(mydns_rr_use_active) ? " AND active=1" : "");

	/* Submit query */
	if (mysql_real_query(mysql, query, querylen) || !(res = mysql_store_result(mysql)))
		return (-1);

	/* Add results to list */
	while ((row = mysql_fetch_row(res)))
	{
		MYDNS_RR *new;

		if (!(new = mydns_parse_rr(row)))
		{
			mysql_free_result(res);
			return (-1);
		}
		if (!first) first = new;
		if (last) last->next = new;
		last = new;
	}
	*rptr = first;
	mysql_free_result(res);
	return (0);
}
/*-----------------------------------------------------------------------------------------------*/

/* vi:set ts=3: */
